﻿using System;
using System.Collections.Generic;
using System.Reflection;
using com.yoozoo.gta.Extension.UGUI.ScreenOrientation;
using com.yoozoo.ResourceUpdate;
using FlowCanvas.Nodes;
using LogSystem;
using Neonagee.LocalPreferences;
using UnityEditor;
using UnityEngine;
using XLua;
using Yoozoo.Framework.Core;



namespace com.yoozoo.gta.Extension.UGUI.ScreenOrientationEx
{


    enum AdapterExecuteOrder
    {
        CanvasScaler = 0,
        RectTransform = 1,
        Transform = 2,
        Default = 100,
        YImageScaler = 200,
        ListView = 1000,
        GridLayout = 1001,
    }
    
    
    public class ScreenOrientManager:Singleton<ScreenOrientManager>
    {
        
        public bool LanscapeOnlyRead = false;
        public bool PortraitOnlyRead = false;
        public bool DebugMode = false;
#if UNITY_EDITOR
        [BlackList]
        public bool AutoAdd
        {
            get => EditorPrefs.GetBool("ScreenOrientManager_AutoAdd", true);
            set => EditorPrefs.SetBool("ScreenOrientManager_AutoAdd", value);
        }
        [BlackList]
        public bool AutoRemove
        {
            get => EditorPrefs.GetBool("ScreenOrientManager_AutoRemove", true);
            set => EditorPrefs.SetBool("ScreenOrientManager_AutoRemove", value);
        }
        
        [BlackList]
        public bool InspectorEditMode
        {
            get => EditorPrefs.GetBool("ScreenOrientManager_InspectorEditMode", false);
            set => EditorPrefs.SetBool("ScreenOrientManager_InspectorEditMode", value);
        }
        [BlackList]
        public bool InspectorAutoAddAdapter  //监听Inspector变化，自动添加、删除无用Adapter
        {
            get => EditorPrefs.GetBool("ScreenOrientManager_InspectorAutoAddAdapter", true);
            set => EditorPrefs.SetBool("ScreenOrientManager_InspectorAutoAddAdapter", value);
        }
        [BlackList] 
        //关闭横竖屏编辑器功能
        public bool CloseScreenOrientEditor
        {
            get => EditorPrefs.GetBool("ScreenOrientManager_CloseScreenOrientEditor", false);
            set => EditorPrefs.SetBool("ScreenOrientManager_CloseScreenOrientEditor", value);
        }
#endif
      


        public UnityEngine.ScreenOrientation CurrentLogicOrientation => m_CurrentLogicOrientation;
      
        private int checkFrameGrap = 10;
        private int frameIndex = 0;
        private UnityEngine.ScreenOrientation m_CurrentLogicOrientation = UnityEngine.ScreenOrientation.LandscapeLeft;
        private readonly SortedDictionary<int, List<ScreenOrientationChangeHandler>> m_OrientationChangeListeners =  
            new SortedDictionary<int, List<ScreenOrientationChangeHandler>>();
        //\private readonly HashSet<ScreenOrientationChangeHandler> m_OrientationChangeListeners = new HashSet<ScreenOrientationChangeHandler>();

        //处理m_OrientationChangeListeners时产生的新的新增和删除操作
        private readonly HashSet<ScreenOrientationChangeHandler> m_OrientationChangeListeners_TempAdd = new HashSet<ScreenOrientationChangeHandler>(128);
        private readonly HashSet<ScreenOrientationChangeHandler> m_OrientationChangeListeners_TempRemove = new HashSet<ScreenOrientationChangeHandler>(128);
        private readonly Dictionary<string,Action<UnityEngine.ScreenOrientation>> m_OrientationChangeActions = new Dictionary<string, Action<UnityEngine.ScreenOrientation>>(256);
        private readonly Dictionary<string,Action<UnityEngine.ScreenOrientation>> m_OrientationChangeActions_TempAdd = new Dictionary<string, Action<UnityEngine.ScreenOrientation>>(64);
        private readonly List<string> m_OrientationChangeActions_TempRemove = new List<string>(64);
        private bool m_init;

        private static bool m_playMode;

        private bool mHandingListener;
        private UnityEngine.ScreenOrientation m_lastOrientation;
        
        private ScreenOrientNativeHelper m_ScreenOrientNativeHelper;
        //Editor切换状态
        public bool EditorChangePlayMode
        {
            get
            {
                return m_playMode;
            }set
            {
                m_playMode = value;
            }
        }


        public int GetListenerCount()
        {
            int count = 0;
            foreach (var list in m_OrientationChangeListeners.Values)
            {
                count += list.Count;
            }
            return count;
        }
        
        /// <summary>
        /// 添加屏幕方向变化监听，  你添加了就一定要移除
        /// </summary>
        /// <param name="key"></param>
        /// <param name="action"></param>
        public void AddOrientationChangeCallBack(string key,Action<UnityEngine.ScreenOrientation> action)
        {
            if (mHandingListener)
            {
                m_OrientationChangeActions_TempAdd[key] = action;
            }
            else
            {
                m_OrientationChangeActions[key] = action;
            }
            action.Invoke(CurrentLogicOrientation);
          
        }
        //移除屏幕监听
        public void RemoveOrientationChangeCallBack(string key)
        {
            if (mHandingListener)
            {
                m_OrientationChangeActions_TempRemove.Add(key);
            }
            else
            {
                m_OrientationChangeActions.Remove(key);
            }
            
        }
        /// <summary>
        /// 移除所有屏幕监听
        /// </summary>
        public void RemoveAllOrientationAction()
        {
            m_OrientationChangeActions.Clear();
        }
        
        /// <summary>
        /// 添加屏幕方向变化监听
        /// </summary>
        /// <param name="listener"></param>
        public void AddOrientationChangeListener(ScreenOrientationChangeHandler listener,bool needForceApply = false)
        {
            if(listener == null)
            {
               Debug.LogError("AddOrientationChangeListener listener is null");
                return;
            }

            if (mHandingListener)
            {
                m_OrientationChangeListeners_TempAdd.Add(listener);
            }
            else
            {
                var key = listener.Order;
                List<ScreenOrientationChangeHandler> list = null;
                if (!m_OrientationChangeListeners.TryGetValue(key, out list))
                {
                    list = new List<ScreenOrientationChangeHandler>(128);
                    m_OrientationChangeListeners.Add(key, list);
                }
                list.Add(listener);
                if (DebugMode)
                {
                    Debug.Log("NO."+GetListenerCount()+"   AddOrientationChangeListener listener: "+listener.transform.name);
                }
               
            }
            listener.ScreenOrientationChange(CurrentLogicOrientation,needForceApply);
           
        }
        /// <summary>
        /// 移除屏幕方向变化监听
        /// </summary>
        /// <param name="listener"></param>
        public void RemoveOrientationChangeListener(ScreenOrientationChangeHandler listener)
        {
            if (listener == null)
            {
               Debug.LogError("RemoveOrientationChangeListener listener is null");
                return;
            }
            if (mHandingListener)
            {
                m_OrientationChangeListeners_TempRemove.Add(listener);
            }
            else
            {
                var key = listener.Order;
                List<ScreenOrientationChangeHandler> list = null;
                if (m_OrientationChangeListeners.TryGetValue(key, out list))
                {
                    bool removeRestult = list.Remove(listener);
                    if (removeRestult)
                    {
                        if (DebugMode)
                        {
                            Debug.Log("count = "+GetListenerCount()+"    RemoveOrientationChangeListener listener: "+ listener + "   "+listener.transform.name );
                        }
                         
                    }
                }
                else
                {
                    //Debug.LogWarningFormat("RemoveOrientationChangeListener error : {0} not found  {1}",key,listener.transform.name);
                }
              
            }
           
           
        }

        public void ForceCleanup()
        {
            m_OrientationChangeListeners.Clear();
            m_OrientationChangeListeners_TempAdd.Clear();
            m_OrientationChangeListeners_TempRemove.Clear();
            
            
            m_OrientationChangeActions.Clear();
            m_OrientationChangeActions_TempAdd.Clear();
            m_OrientationChangeActions_TempRemove.Clear();
            
        }
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
        static void InitializeOnLoadMethod()
        {
            ScreenOrientManager.GetInstance().Initialize();
            
        }
        private const string ScreenOrientLocalKey = "ScreenOrientUserSetting";
      
        public override void Initialize(Options options=null)
        {
            if (m_init) return;
            
            m_init = true;
            UnityEngine.Debug.Log($"ScreenOrientation  Initialize");
            m_ScreenOrientNativeHelper = new ScreenOrientNativeHelper();
#if UNITY_EDITOR || (!UNITY_ANDROID && !UNITY_IOS)
             var currentOrientataion = Screen.orientation;
            //从本地读取用户设置的屏幕方向（如果没设置过默认为横屏）
            UnityEngine.ScreenOrientation initOrientation = (UnityEngine.ScreenOrientation)LocalPrefs.GetInt(ScreenOrientLocalKey, (int)currentOrientataion);

            UnityEngine.Debug.Log($"ScreenOrientation  Initialize  initOrientation =  {initOrientation}");
            //如果宽高比<1.2  强制设置为横屏
            if ((initOrientation == UnityEngine.ScreenOrientation.Portrait ||
                 initOrientation == UnityEngine.ScreenOrientation.PortraitUpsideDown) && !IsSupportPortraitRotation())
            {
                initOrientation = UnityEngine.ScreenOrientation.LandscapeLeft;
                UnityEngine.Debug.Log($" ScreenOrientation Initialize set initOrientation =  {initOrientation}");
            }
            // //用当前的朝向初始化
            // DispatchOrientationChange(Screen.orientation);
            //设置应该的屏幕方向
            SetScreenOrientation(initOrientation);
#endif
        }

        /// <summary>
        /// 用来监听屏幕方向变化
        /// </summary>
        [BlackList]
        public override void Update()
        {
            //监听GameView的变化,切换横竖屏
            UpdateOrientionByGameView();
        }
        [BlackList]
        public void UpdateOrientionByGameView()
        {
            var gameViewSize = GameViewSize();
            if(gameViewSize.x >= gameViewSize.y && m_CurrentLogicOrientation != UnityEngine.ScreenOrientation.LandscapeLeft)
            {
                DispatchOrientationChange(UnityEngine.ScreenOrientation.LandscapeLeft);
            }
            else if(gameViewSize.y > gameViewSize.x && m_CurrentLogicOrientation != UnityEngine.ScreenOrientation.Portrait)
            {
                DispatchOrientationChange(UnityEngine.ScreenOrientation.Portrait);
            }
        }
        private void OnDisable()
        {
            
        }
        
        /// <summary>
        /// 设置屏幕方向, 来自系统默认&玩家设置
        /// </summary>
        /// <param name="orientation"></param>
        public void SetScreenOrientation(UnityEngine.ScreenOrientation orientation)
        {
            if(!m_init)
            {
                UnityEngine.Debug.LogError("UnityEngine ScreenOrientDetector not init");
                return;
            }

            if (orientation == UnityEngine.ScreenOrientation.Portrait ||
                orientation == UnityEngine.ScreenOrientation.PortraitUpsideDown)
            {
                OpenPortrait();
            }else if (orientation == UnityEngine.ScreenOrientation.LandscapeLeft ||
                      orientation == UnityEngine.ScreenOrientation.LandscapeRight)
            {
                OpenLandscapeLeft();
            }else if(orientation == UnityEngine.ScreenOrientation.AutoRotation)
            {
                OpenAutoRotation();
            }
            else
            {
                UnityEngine.Debug.LogError("ScreenOrientation  SetScreenOrientation error, use default landscape left");
                OpenLandscapeLeft();
            }
            
        }
        /// <summary>
        /// 通知外部UI屏幕方向变化    
        /// </summary>
        /// <param name="orientation"></param>
        [BlackList]
        public void DispatchOrientationChange(UnityEngine.ScreenOrientation orientation)
        {
            UnityEngine.Debug.Log($" ScreenOrientation  DispatchOrientationChange {orientation}  currentGameViewSize = {GameViewSize()}");
            
#if !UNITY_EDITOR
            if (m_CurrentLogicOrientation != orientation)
            {
#endif
                m_CurrentLogicOrientation = orientation;
                UnityEngine.Debug.Log($" ScreenOrientation   设置ScreenOrientManager的屏幕方向： DispatchOrientationChange orientation:"+orientation);

                
                mHandingListener = true;
                foreach (var listenerList in m_OrientationChangeListeners.Values)
                {
                    foreach (var listener in listenerList)
                    {
                        if ( null == listener)
                        {
                            UnityEngine.Debug.Log($" ScreenOrientation  Listener has been destroyed or is not active.");
                            continue;
                        }
                        try
                        {
                            listener.ScreenOrientationChange(orientation);
                        }
                        catch (Exception e)
                        {
                            if (listener && listener.transform)
                            {
                                UnityEngine.Debug.LogError(" ScreenOrientation  执行ScreenOrientationChange 出现异常：  "+listener.transform.name);
                            }
                        
                            UnityEngine.Debug.LogError($" ScreenOrientation listener    {e.Message}");
                        }
                    }
                }

                foreach (var action in m_OrientationChangeActions.Values)
                {
                    try
                    {
                        action?.Invoke(orientation);
                    }
                    catch (Exception e)
                    {
                        UnityEngine.Debug.LogError($" ScreenOrientation m_OrientationChangeActions    {e.Message}");
                    }
                }
                mHandingListener = false;
                
                foreach (var listener in m_OrientationChangeListeners_TempAdd)
                {
                    AddOrientationChangeListener(listener);
                }
                m_OrientationChangeListeners_TempAdd.Clear();
                foreach (var listener in m_OrientationChangeListeners_TempRemove)
                {
                    RemoveOrientationChangeListener(listener);
                }
                
                m_OrientationChangeListeners_TempRemove.Clear();
                foreach (var action in m_OrientationChangeActions_TempAdd)
                {
                    m_OrientationChangeActions[action.Key] = action.Value;
                }
                m_OrientationChangeActions_TempAdd.Clear();
                foreach (var key in m_OrientationChangeActions_TempRemove)
                {
                    m_OrientationChangeActions.Remove(key);
                }
                m_OrientationChangeActions_TempRemove.Clear();
#if !UNITY_EDITOR
            }
#endif
        }
        
        private Vector2Int tempScreenSize = new Vector2Int(Screen.width,Screen.height);
        private bool openAutoCheck = false;
        private int waitFrameCount;
        public Vector2Int GameViewSize()
        {
            
#if UNITY_EDITOR 
            var mouseOverWindow = UnityEditor.EditorWindow.mouseOverWindow;
            System.Reflection.Assembly assembly = typeof(UnityEditor.EditorWindow).Assembly;
            System.Type type = assembly.GetType("UnityEditor.PlayModeView");

            Vector2 size = (Vector2)type.GetMethod(
                "GetMainPlayModeViewTargetSize",
                System.Reflection.BindingFlags.NonPublic |
                System.Reflection.BindingFlags.Static
            ).Invoke(mouseOverWindow, null);

            return new Vector2Int((int)size.x,(int)size.y);
#else
         
            tempScreenSize.x = Screen.width;
            tempScreenSize.y = Screen.height;
            //UnityEngine.Debug.Log(" ScreenOrientation  tempScreenSize  width= " + tempScreenSize.x + " tempScreenSize= " + tempScreenSize.y);
            return tempScreenSize;
#endif
        }
#if UNITY_EDITOR
       
        [BlackList]
        public void Refresh()
        {
           // m_OrientationChangeListeners.Clear();
            OnValidate();
            //var handerList = GameObject.FindObjectsOfType<ScreenOrientationChangeHandler>();
            // foreach (var handler in m_OrientationChangeListeners)
            // {
            //     m_OrientationChangeListeners.Add(handler);
            //     handler.ScreenOrientationChange(m_CurrentOrientation);
            // }
        }
        
        [BlackList]
        public void JustRefreshOrientation()
        {
            var gameViewSize = GameViewSize();
            if(gameViewSize.x >= gameViewSize.y && m_CurrentLogicOrientation != UnityEngine.ScreenOrientation.LandscapeLeft)
            {
                m_CurrentLogicOrientation = UnityEngine.ScreenOrientation.LandscapeLeft;
            }
            else if(gameViewSize.y > gameViewSize.x && m_CurrentLogicOrientation != UnityEngine.ScreenOrientation.Portrait)
            {
                m_CurrentLogicOrientation = UnityEngine.ScreenOrientation.Portrait;
            }

        }
        [BlackList]
        public void OnValidate()
        {
            if (Application.isPlaying) return;
            m_CurrentLogicOrientation = UnityEngine.ScreenOrientation.Unknown;
            m_init = true;
            //获取gameview的分辨率
            var gameViewSize = GameViewSize();
            Debug.Log("ScreenOrientManager： GameView Resolution: x=" + gameViewSize.x + " y=" + gameViewSize.y);
            if (gameViewSize.x > gameViewSize.y)
            {
               Debug.Log("GameView Orientation: Landscape");
            }
            else
            {
               Debug.Log("GameView Orientation: Portrait");
            }
            UpdateOrientionByGameView();
        }
        
          private  void ChangeGameViewOrientation(UnityEngine.ScreenOrientation orientation)
        {
            
            var gameViewSize = GameViewSize();
            
            if((gameViewSize.x > gameViewSize.y && orientation == UnityEngine.ScreenOrientation.LandscapeLeft) ||
               (gameViewSize.y > gameViewSize.x && orientation == UnityEngine.ScreenOrientation.Portrait))
            {
                return;
            }
            var sizesType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameViewSizes");
            var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);
            var instanceProp = singleType.GetProperty("instance");
            object gameViewSizesInstance = instanceProp.GetValue(null, null);
            
            var gameViewType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameView");
            var gameViewSizeGroup = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameViewSizeGroupType");
            var currentGroupInstance  = sizesType.GetProperty("currentGroup").GetValue(gameViewSizesInstance, null);
            
            //获取currentGroupInstance的总数
            var GetTotalCount = currentGroupInstance.GetType().GetMethod("GetTotalCount");
            int groupCount = (int)GetTotalCount.Invoke(currentGroupInstance, null);
            int gameviewIndex = 0;
            //遍历currentGroupInstance中所有的GameviewSize
            for (int i = 0; i < groupCount; i++)
            {
                var group = currentGroupInstance;

                var getGameViewSize = group.GetType().GetMethod("GetGameViewSize");
                var gameViewSizeType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameViewSize");
                var gameViewSizeInstance = getGameViewSize.Invoke(group, new object[] { i });
                var width = (int)gameViewSizeType.GetProperty("width").GetValue(gameViewSizeInstance);
                var height = (int)gameViewSizeType.GetProperty("height").GetValue(gameViewSizeInstance);
                if (width == gameViewSize.y && height == gameViewSize.x)
                {
                    gameviewIndex = i;
                    break;
                }
            }
            
            var gvWndType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameView");
            var gvWnd = EditorWindow.GetWindow(gvWndType);
            var SizeSelectionCallback = gvWndType.GetMethod("SizeSelectionCallback",
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            SizeSelectionCallback.Invoke(gvWnd, new object[] { gameviewIndex, null });
            
        }  
        
#endif

        public bool IsLandscape()
        {
            return m_CurrentLogicOrientation == UnityEngine.ScreenOrientation.LandscapeLeft ||
                   m_CurrentLogicOrientation == UnityEngine.ScreenOrientation.LandscapeRight;
        }
        
        public bool IsPortrait()
        {
            return m_CurrentLogicOrientation == UnityEngine.ScreenOrientation.Portrait ||
                   m_CurrentLogicOrientation == UnityEngine.ScreenOrientation.PortraitUpsideDown;
        }
        /// <summary>
        /// 打开自动旋转
        /// </summary>
        public void OpenAutoRotation()
        {
            Screen.orientation = UnityEngine.ScreenOrientation.AutoRotation;
            Screen.autorotateToLandscapeLeft = true;
            Screen.autorotateToLandscapeRight = false; 
            Screen.autorotateToPortrait = true;
            Screen.autorotateToPortraitUpsideDown = false;
            Debug.Log(LogModule.ScreenOrientation,$" Call  OpenAutoRotation ");
        }    
       
        public void SaveToLocal(UnityEngine.ScreenOrientation orientation)
        {
            
            SetScreenOrientation(orientation);
            
            //设置到本地
            LocalPrefs.SetInt(ScreenOrientLocalKey, (int)orientation);
            try
            {
                m_ScreenOrientNativeHelper.SaveToLocal(orientation);
            }catch (Exception e)
            {
                Debug.LogError("ScreenOrientation  SaveToLocal error: "+e.Message);
            }
           
        }

        public void OpenLandscapeLeft()
        {
            Screen.orientation = UnityEngine.ScreenOrientation.LandscapeLeft;
            UnityEngine.Debug.Log($" ScreenOrientation Call  OpenLandscapeLeft ");
#if UNITY_EDITOR
            ChangeGameViewOrientation(UnityEngine.ScreenOrientation.LandscapeLeft);
#endif
            
        }

      
        public void OpenPortrait()
        {
            
            Screen.orientation = UnityEngine.ScreenOrientation.Portrait;
            UnityEngine.Debug.Log($" ScreenOrientation  Call  OpenPortrait ");
          
#if UNITY_EDITOR
            ChangeGameViewOrientation(UnityEngine.ScreenOrientation.Portrait);
#endif
        }

        // 运行中强制设置成横屏
        public void ForceChangeLandscape()
        {
            UnityEngine.Debug.Log($" ScreenOrientation Call  ForceChangeLandscape ");
            if (m_CurrentLogicOrientation != UnityEngine.ScreenOrientation.LandscapeLeft && m_CurrentLogicOrientation != UnityEngine.ScreenOrientation.LandscapeRight)
            {
                m_lastOrientation = m_CurrentLogicOrientation;   
                OpenLandscapeLeft();
            }
           
        }
        //应该跟上面的是一对，用来恢复到之前的状态
        public void RevertForceChangeLandscape()
        {
            UnityEngine.Debug.Log($" ScreenOrientation Call  RevertForceChangeLandscape ");
            if (m_CurrentLogicOrientation == UnityEngine.ScreenOrientation.LandscapeLeft || m_CurrentLogicOrientation == UnityEngine.ScreenOrientation.LandscapeRight)
            {
                if (m_lastOrientation == UnityEngine.ScreenOrientation.AutoRotation)
                {
                    OpenAutoRotation();
                    m_lastOrientation = UnityEngine.ScreenOrientation.Unknown;
                }else if (m_lastOrientation == UnityEngine.ScreenOrientation.Portrait || m_lastOrientation == UnityEngine.ScreenOrientation.PortraitUpsideDown)
                {
                    OpenPortrait();
                    m_lastOrientation = UnityEngine.ScreenOrientation.Unknown;
                }
            }
        }
        
        // 获取是否是竖屏
        public bool GetScreenOrientationIsPortrait()
        {
            bool isPortrait = false;
            isPortrait = CurrentLogicOrientation == UnityEngine.ScreenOrientation.Portrait ||
                         CurrentLogicOrientation == UnityEngine.ScreenOrientation.PortraitUpsideDown;
            return isPortrait;
        }
        //是否支持竖屏(当屏幕宽高比小于1.2时不支持竖屏)
        public bool IsSupportPortraitRotation()
        {
#if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX
            return false;
#else
            var gameViewSize = GameViewSize();
            var tempSize = new Vector2();
            tempSize.x = Math.Max(gameViewSize.x,gameViewSize.y);
            tempSize.y = Math.Min(gameViewSize.x,gameViewSize.y);
            
            double aspect = Math.Round(tempSize.x/tempSize.y, 2);
            if(aspect < 1.2f)
            {
                //UnityEngine.Debug.Log($" ScreenOrientation 宽高比： {aspect} 不支持竖屏");
                return false;
            }
            //UnityEngine.Debug.Log($" ScreenOrientation  宽高比： {aspect}");
            return true;
#endif
        }
    }
}